#include "../../include/http/HttpServer.h"
#include <any>
#include <functional>
#include <memory>

namespace http
{
    HttpServer::HttpServer(muduo::net::EventLoop* loop, const muduo::net::InetAddress& listenAddr, const std::string& name)
        : _mainLoop(loop),
          _listenAddr(listenAddr),
          _server(loop, listenAddr, name, muduo::net::TcpServer::kReusePort)
    {
        _server.setConnectionCallback(
            std::bind(&HttpServer::OnConnection, this, std::placeholders::_1));
        _server.setMessageCallback(
            std::bind(&HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
        
        // 设置默认的HTTP回调函数
        SetHttpCallback(std::bind(&HttpServer::handleRequest, this, std::placeholders::_1, std::placeholders::_2));
    }
    
    void HttpServer::start()
    {
        _server.ipPort();
        _server.start();
        _mainLoop->loop();
    }
    void HttpServer::SetHttpCallback(const HttpCallback &cb)
    {
        _httpCallback = cb;
    }
    void HttpServer::initialize()
    {
        _server.setConnectionCallback(
            std::bind(&HttpServer::OnConnection, this, std::placeholders::_1));
        _server.setMessageCallback(
            std::bind(&HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
    }
    // 新连接建立时回调函数
    // 每次客户端连接服务器时，都会调用这个函数，该函数是muduo库提供的接口注册的回调函数
    void HttpServer::OnConnection(const muduo::net::TcpConnectionPtr &conn)
    {
        // 给连接设置一个HttpContext上下文，提取封装请求报文信息
        if (conn->connected())
        {
            conn->setContext(HttpContext());
        }
    }

    // 消息到达时回调函数
    // 服务端在接收到跟服务端建立连接的客户端的数据时，会调用这个函数，该函数是muduo库提供的接口注册的回调函数
    void HttpServer::OnMessage(const muduo::net::TcpConnectionPtr &conn,
                               muduo::net::Buffer *buf,
                               muduo::Timestamp receiveTime)
    {
        try
        {
            // HttpContext对象用于解析出buf中的请求报文信息，并封装到HttpRequest对象中
            HttpContext *context = boost::any_cast<HttpContext>(conn->getMutableContext());
            if (!context->parseRequest(buf, receiveTime))
            {
                // 如果请求不完整，则发送400错误，并关闭连接
                conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
                conn->shutdown();
            }
            // 如果请求完整，则处理请求，调用业务层注册的回调函数
            if (context->isComplete())
            {
                // 处理请求，调用业务层注册的回调函数
                OnRequest(conn, context->getRequest());
                context->reset(); // 重置上下文，为下一次请求做准备
            }
        }
        catch (const std::exception &e)
        {
            // 如果解析请求报文信息时发生异常，则发送400错误，并关闭连接
            LOG_ERROR << "HttpServer::OnMessage error: " << e.what();
            conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
            conn->shutdown();
        }
    }

    // 接收到消息回调后调用的处理函数
    void HttpServer::OnRequest(const muduo::net::TcpConnectionPtr &conn, const HttpRequest &req)
    {
        const std::string &connection = req.getHeader("Connection");                                                     // 获取连接
        bool close = (connection == "close") || (req.getVersion() == "HTTP/1.0" && connection != "Keep-Alive"); // 如果连接为close或者版本为1.0且连接不为Keep-Alive，则关闭连接
        HttpResponse response(close);                                                                                    // 创建响应
        //处理OPTIONS请求
        if(req.getMethod() == HttpRequest::Options)
        {
            response.setStatusLine(req.getVersion(), HttpResponse::Ok, "OK");
            response.addHeader("Access-Control-Allow-Origin", "*");                            // 允许的源
            response.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");          // 允许的请求方法
            response.addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); // 允许的请求头
            response.addHeader("Access-Control-Allow-Credentials", "true");                    // 允许的凭据
            response.addHeader("Access-Control-Max-Age", "86400");                             // 允许的缓存时间
        }
        // 根据请求报文信息来封装响应报文
        _httpCallback(req, response); // 执行onHttpCallback回调函数

        // 可以给response设置一个成员，判断是否请求的是文件，如果是文件，则设置为true，并且存在文件位置这里send出去
        muduo::net::Buffer buf;
        response.appendToBuffer(&buf);
        conn->send(&buf);
        if (response.isCloseConnection())
        {
            conn->shutdown();
        }
    }

    void HttpServer::handleRequest(const HttpRequest &req, HttpResponse &resp)
    {
        try
        {
            _middlewareChain.processBefore(req);
            if (!_router.route(req, resp))
            {
                std::cout << "请求方式，url是：" << req.getMethod() << " " << req.getPath() << std::endl;
                std::cout << "未找到路由" << std::endl;
                resp.setStatusLine(req.getVersion(), HttpResponse::NotFound, "Not Found");
                resp.setCloseConnection(true);
            }
            _middlewareChain.processAfter(resp);
        }
        catch (const HttpResponse &response)
        {
            //处理中间件抛出的响应（如CORS预检请求）
            resp = response;
        }
        // 如果处理请求时发生异常，则发送500错误，并关闭连接
        catch (const std::exception &e)
        {
            resp.setStatusCode(HttpResponse::InternalServerError);
            resp.setBody(e.what());
        }
    }

}